﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.SqlClient;

using EzDesk.Core.Model;
using EzDesk.Utility;
using EzDesk.Core.CoreImpl;
using EzDesk.Core.CoreImpl.Repositories;
using EzDesk.Core.CoreImpl.Filters;
using System.Diagnostics;
using EzDesk.Utility.EzML;
using EzDesk.Core.CoreImpl.Services.AppPortal;
using System.Configuration;

namespace EzDesk.Core.CoreImpl
{
    public partial class CoreService : ICoreService
    {
        private UserRepository _userRepository;
        private DeptRepository _deptRepository;
        private AppRepository _appRepository;
        private PositionRepository _positionRepository;
        private GroupRepository _groupRepository;
        private FeedRepository _feedRepository;
        private FeedTemplateRepository _feedTemplateRepository;
        private IAppPortalService _appPortalService;
        private IAppSessionService _appSessionService;

        public CoreService(
            UserRepository userRepository,
            DeptRepository deptRepository,
            AppRepository appRepository,
            PositionRepository positionRepository,
            GroupRepository groupRepository,
            FeedRepository updateFeedRepository,
            FeedTemplateRepository feedTemplateReposiory,
            IAppPortalService appPortalService,
            IAppSessionService appSessionService
            )
        {
            this._appRepository = appRepository;
            this._deptRepository = deptRepository;
            this._userRepository = userRepository;
            this._positionRepository = positionRepository;
            this._groupRepository = groupRepository;
            this._feedRepository = updateFeedRepository;
            this._feedTemplateRepository = feedTemplateReposiory;

            this._appPortalService = appPortalService;
            this._appSessionService = appSessionService;
        }

        // todo: 使用DI重构
        public CoreService()
            : this(
            new UserRepository(),
            new DeptRepository(),
            new AppRepository(),
            new PositionRepository(),
            new GroupRepository(),
            new FeedRepository(),
            new FeedTemplateRepository(),
            new AppPortalService(),
            new AppSessionService()
            )
        {
        }


        private ICoreService self
        {
            get
            {
                return (ICoreService)this;
            }
        }


        private Guid[] convertSingleIdToIdCollection(Guid singleId)
        {
            Guid[] guids = new Guid[1]
            {
                singleId
            };
            return guids;
        }

        private Guid[] convertIdStrsToIdCollection(string idStrs)
        {
            var idStrList = idStrs.Split(',');

            IList<Guid> idList = new List<Guid>();

            foreach (var idStr in idStrList)
            {
                Guid result;
                if (Guid.TryParse(idStr, out result))
                {
                    idList.Add(result);
                }
            }
            return idList.ToArray();
        }


        string ICoreService.AppPortalUrl
        {
            get
            {
                return ConfigurationManager.AppSettings["AppPortalLocation"];
            }
        }

        string ICoreService.EzDeskUrl
        {
            get
            {
                return ConfigurationManager.AppSettings["EzDeskLocation"];
            }
        }


        //#region ICoreService Members

        UserProfile ICoreService.GetUserProfileByUserName(string userName)
        {
            return _userRepository.GetAll()
                .ByUserName(userName);
        }

        UserProfile ICoreService.GetUserProfileById(Guid userId)
        {
            return _userRepository.GetById(userId);
        }

        UserProfile ICoreService.CreateEmptyUserProfile(string userName)
        {
            return _userRepository.CreateEmptyUser(userName);
        }

        void ICoreService.DeleteUserProfile(Guid userId)
        {
            _userRepository.Delete(userId);
        }

        SimpleUser ICoreService.GetSimpleUserById(Guid userId)
        {
            return  _userRepository.GetSimpleUserById(userId);
        }

        IList<SimpleUser> ICoreService.GetSimpleUserInfos(Guid[] userIdCollection)
        {
            var allSimpleInfo = _userRepository.GetAllSimpleUserInfo();
            IList<SimpleUser> users = new List<SimpleUser>();
            foreach (Guid id in userIdCollection)
            {
                users.Add(allSimpleInfo.ByUserId(id));
            }
            return users;
        }

        IList<SimpleUser> ICoreService.GetSimpleUserInfos(string memberstring)
        {
            Guid[] userIdsToSent =
                self.GetAllUsersByMemberString(memberstring)
                .Select(p => p.Id)
                .ToArray();

            return self.GetSimpleUserInfos(userIdsToSent);
        }

        SimpleUser ICoreService.GetSimpleUserInfoByUserName(string userName)
        {
            return _userRepository.GetAllSimpleUserInfo()
                .ByUserName(userName);
        }

        IList<SimpleUser> ICoreService.GetUsersInDept(Guid deptId)
        {
            return _userRepository.GetAll()
                .InDept(deptId)
                .ToList();
        }

        IList<Dept> ICoreService.GetAllDepts()
        {
            return _deptRepository.GetAll()
                .ToList();
        }

        Dept ICoreService.GetDeptById(Guid deptId)
        {
            return _deptRepository.GetById(deptId);
        }

        Dept ICoreService.CreateDept(string deptName)
        {
            //判断名字不重复
            if (_deptRepository.GetAll().ByDeptName(deptName) != null)
            {
                throw new Exception("Duplicated Dept Name");
            }

            //创建相应分组
            var newGroup = self.CreateGroup(null, null, deptName, 1 /* GroupType = 1 部门组 */);

            // 创建新的Dept 写入
            var newDept = new Dept()
            {
                Id = new Guid(),
                DeptName = deptName,
                GroupId = newGroup.Id,
            };
            _deptRepository.Add(newDept);
            return newDept;
        }

        void ICoreService.ChangeUserDept(Guid userId, Guid deptId)
        {
            Dept dept = _deptRepository.GetById(deptId);
            if (dept == null)
            {
                throw new Exception("Dept not found!!!");
            }

            // 从当前部门删除
            self.RemoveUserFromCurrentDept(userId);

            // 添加入新的部门
            var user = _userRepository.GetById(userId);
            user.DeptId = deptId;
            _userRepository.Update(user);

            // 将用户加入到对应的Group
            self.AddUserInGroup(dept.GroupId.GetValueOrDefault(), userId);

        }

        void ICoreService.ChangeUserReportId(Guid userId, Guid reportId)
        {
            //todo: validate repostId

            var user = _userRepository.GetById(userId);
            user.ReportId = reportId;
            user.ReportPath = user.ReportPath + "|" + reportId;
            _userRepository.Update(user);
        }

        void ICoreService.ChangeUserPosition(Guid userId, Guid positionId)
        {
            // validate positionId

            var user = _userRepository.GetById(userId);
            user.PositionId = positionId;
            _userRepository.Update(user);
        }

        IList<SimpleUser> ICoreService.GetUsersInPosition(Guid posId)
        {
            return _userRepository.GetAll()
                .InPosition(posId)
                .ToList();
        }

        IList<SimpleUser> ICoreService.GetDirectReports(Guid userId)
        {
            throw new NotImplementedException();
            //        try
            //        {
            //            using (EzDeskDataContext dc = new EzDeskDataContext())
            //            {
            //                return dc.ez_UserProfiles.Where(u => u.ReportPath.EndsWith(userId.ToString())).Select(u => u.ToSimpleUser()).ToList();
            //            }
            //        }
            //        catch (Exception ex)
            //        {
            //            ErrorLog.WriteLog(ex, null, -1);
            //            throw ex;
            //        }
        }

        IList<SimpleUser> ICoreService.GetAllReports(Guid userId)
        {
            throw new NotImplementedException();
            //        try
            //        {
            //            using (EzDeskDataContext dc = new EzDeskDataContext())
            //            {
            //                return dc.ez_UserProfiles.Where(u => u.ReportPath.IndexOf(userId.ToString())>-1).Select(u => u.ToSimpleUser()).ToList();
            //            }
            //        }
            //        catch (Exception ex)
            //        {
            //            ErrorLog.WriteLog(ex, null, -1);
            //            throw ex;
            //        }
        }


        void ICoreService.RemoveUserFromCurrentDept(Guid userId)
        {
            var user = _userRepository.GetById(userId);

            //todo: check if user is in a dept

            var dept = _deptRepository.GetById(user.DeptId.GetValueOrDefault());

            if (user.DeptId.HasValue)
            {
                self.RemoveUserFromGroup(dept.GroupId.GetValueOrDefault(), user.Id);
                user.DeptId = null;
            }
            _userRepository.Update(user);
        }

        void ICoreService.ChangeDeptName(Guid deptId, string deptName)
        {
            var dept = _deptRepository.GetById(deptId);

            // todo: check if dept's group is null

            var group = _groupRepository.GetById(dept.GroupId.GetValueOrDefault());
            group.Description = deptName;
            _groupRepository.Update(group);

            dept.DeptName = deptName;
            _deptRepository.Update(dept);
        }

        void ICoreService.DeleteDept(Guid deptId)
        {
            var dept = _deptRepository.GetById(deptId);
            // todo: check if dept has a groupId
            _groupRepository.Delete(dept.GroupId.GetValueOrDefault());
            _deptRepository.Delete(dept.Id);
        }

        Group ICoreService.CreateGroup(SimpleUser[] userIds, Group[] groupIds, string descrition, int type)
        {
            var group = new Group();
            group.Id = Guid.NewGuid();

            List<string> ids = new List<string>();
            ids.Add(userIds.Join(",", u => u.Id.ToString()));
            ids.AddRange(groupIds.ToStringArrary(g => g.Id.ToString()));
            group.MemberString = ids.Join("|");

            if (string.IsNullOrEmpty(descrition))
            {
                group.Description = userIds.Join(";", u => u.UserName) + groupIds.Join(";", g => g.Description);
            }
            else
                group.Description = descrition;

            _groupRepository.Add(group);
            return group;

        }

        void ICoreService.ChangeGroupDescription(Guid groupId, string description)
        {
            var group = _groupRepository.GetById(groupId);
            group.Description = description;
            _groupRepository.Update(group);
        }

        void ICoreService.DeleteGroup(Guid groupId)
        {
            _groupRepository.Delete(groupId);
        }


        Group ICoreService.GetGroupById(Guid groupId)
        {
            return self.GetGroups(
                convertSingleIdToIdCollection(groupId)
                )
                .FirstOrDefault();
        }

        IList<Group> ICoreService.GetGroups(string groupIdStrs)
        {
            return self.GetGroups(
                convertIdStrsToIdCollection(groupIdStrs)
                );
        }


        IList<Group> ICoreService.GetGroups(Guid[] groupIdCollection)
        {
            IList<Group> groupList = new List<Group>();
            foreach (var gid in groupIdCollection)
            {
                groupList.Add(_groupRepository.GetById(gid));
            }
            return groupList;
        }


        IDictionary<Guid, string> ICoreService.GetChildrenInGroup(Guid groupId)
        {
            var children = new Dictionary<Guid, string>();

            var group = _groupRepository.GetById(groupId);
            string memberString = group.MemberString;

            var usersPair = _userRepository.GetAll()
                .Where(p => memberString.IndexOf(p.Id.ToString()) > -1)
                .Select(p => new KeyValuePair<Guid, string>(p.Id, "User"));
            children.AddRange(usersPair.ToArray());

            var groupsPair = _groupRepository.GetAll()
                .Where(p => memberString.IndexOf(p.Id.ToString()) > -1)
                .Select(p => new KeyValuePair<Guid, string>(p.Id, "Group"));

            children.AddRange(groupsPair.ToArray());

            return children;
        }

        IList<Guid> ICoreService.GetAllUserIdsInGroup(Guid groupId)
        {
            IList<Guid> allUserIds = new List<Guid>();
            var userIds = getChildren(groupId).Distinct().ToList();
            foreach (var userIdStr in userIds)
            {
                var simpleUser = _userRepository.GetSimpleUserById(new Guid(userIdStr));
                if (simpleUser == null)
                {
                    throw new Exception("UserId Not Found!");
                }
                allUserIds.Add(new Guid(userIdStr));
            }

            return allUserIds;
        }

        IList<SimpleUser> ICoreService.GetAllUsersInGroup(Guid groupId)
        {
            return self.GetSimpleUserInfos(self.GetAllUserIdsInGroup(groupId).ToArray());
        }

        private IEnumerable<string> getChildren(Guid groupId)
        {
            var group = _groupRepository.GetById(groupId);

            // 处理特殊的Memberstring
            string memberString = group.MemberString;

            IEnumerable<string> m_userIdStrs = new List<string>() ;
            if (memberString == "everyone")
            {
                // 所有人
                m_userIdStrs = _userRepository.GetAll()
                    .Select(p => p.Id.ToString())
                    .ToArray();
            }
            else
            {
                string[] strs = memberString.Split('|');

                if (strs.Length > 0)
                {
                    if (!string.IsNullOrEmpty(strs[0]))
                    {
                        m_userIdStrs = strs[0].Split(',');
                    }
                }

                if (strs.Length > 1)
                {
                    string[] m_groupIdStrs = strs[1].Split(',');
                    for (int i = 0; i < m_groupIdStrs.Length; i++)
                    {
                        m_userIdStrs = m_userIdStrs.Union(
                            getChildren(new Guid(m_groupIdStrs[i]))
                            );
                    }
                }
            }
            return m_userIdStrs.Distinct();
        }

        Group ICoreService.GetGroupByDescription(string description)
        {
            return _groupRepository.GetAll()
                .Where(p => p.Description == description)
                .SingleOrDefault();
        }

        Group ICoreService.GetGroupMemberstring(string memberstring)
        {
            return _groupRepository.GetAll()
                .Where(p => p.MemberString == memberstring)
                .SingleOrDefault();
        }

        void ICoreService.AddUserInGroup(Guid targetGroupId, Guid userId)
        {
            var group = _groupRepository.GetById(targetGroupId);
            if (String.IsNullOrEmpty(group.MemberString))
            {
                group.MemberString = userId.ToString();
            }
            else
            {
                group.MemberString = String.Format("{0},{1}", userId.ToString(), group.MemberString);
            }
            _groupRepository.Update(group);
        }

        void ICoreService.AddGroupInGroup(Guid targetGroupId, Guid groupId)
        {
            var group = _groupRepository.GetById(targetGroupId);
            group.MemberString = string.Format("{0},{1}", group.MemberString, groupId);
            _groupRepository.Update(group);
        }

        void ICoreService.RemoveUserFromGroup(Guid targetGroupId, Guid userId)
        {
            var group = _groupRepository.GetById(targetGroupId);

            string[] groupIds = group.MemberString.Split('|');
            List<string> userIds = groupIds[0].Split(',').ToList();
            userIds.Remove(userId.ToString());
            groupIds[0] = String.Join(",", userIds.ToArray());
            group.MemberString = string.Join("|", groupIds);

            _groupRepository.Update(group);

        }

        void ICoreService.RemoveGroupFromGroup(Guid targetGroupId, Guid groupId)
        {
            var group = _groupRepository.GetById(targetGroupId);

            List<string> groupIds = group.MemberString.Split('|').ToList();
            groupIds.Remove(groupId.ToString());
            group.MemberString = string.Join("|", groupIds.ToArray());

            _groupRepository.Update(group);
        }



        IList<Guid> ICoreService.GetAllUserIdsByMemberString(string memberString)
        {
            return getAllUserIdsByMemberString(memberString);
        }

        IList<SimpleUser> ICoreService.GetAllUsersByMemberString(string memberString)
        {
            return
                self.GetSimpleUserInfos(
                    self.GetAllUserIdsByMemberString(memberString).ToArray()
                    );
        }

        IList<Guid> getAllUserIdsByMemberString(string memberString, Guid? sender = null, bool isIncludingSender = false)
        {
            var groupId = getGroupIdByMemberString(memberString);

            IList<Guid> allUserIds = self.GetAllUserIdsInGroup(groupId);

            if (sender.HasValue)
            {
                int senderIndex = allUserIds.IndexOf(sender.GetValueOrDefault());
                if (senderIndex >= 0 && !isIncludingSender)
                {
                    // 找到发送者 且 不需要包含发送者， 将发送者移除
                    allUserIds.RemoveAt(senderIndex);
                }
                else if (senderIndex < 0 && isIncludingSender)
                {
                    // 未找到发送者 且 需要包含发送者， 将发送者加入列表
                    allUserIds.Add(sender.GetValueOrDefault());
                }
            }
            return allUserIds;
        }

        IDictionary<Guid, string> ICoreService.GetChildrenByMemberString(string memberString)
        {
            var groupId = getGroupIdByMemberString(memberString);

            return self.GetChildrenInGroup(groupId);
        }

        // 这个方法进行动态创建Group
        // 如果请求的MemberString不存在，则创建动态的Group
        private Guid getGroupIdByMemberString(string memberString)
        {
            if (string.IsNullOrEmpty(memberString))
            {
                throw new Exception("memberstring cannot be Null!");
            }

            Group group = _groupRepository.GetAll().Where(p => p.MemberString == memberString).SingleOrDefault();

            if (group == null)
            {
                group = new Group()
                    {
                        Id = Guid.NewGuid(),
                        Description = null,
                        MemberString = memberString,
                        Type = 2 /* 一般组 */,
                    };
                _groupRepository.Add(group);
            }
            return group.Id;
        }

        IList<Position> ICoreService.GetPositions()
        {
            return _positionRepository.GetAll()
                .ToList();
        }

        Position ICoreService.CreatePosition(string descrition, int priority)
        {
            var position = new Position()
            {
                Id = Guid.NewGuid(),
                Description = descrition,
                Priority = priority,
            };
            _positionRepository.Add(position);
            return position;
        }

        void ICoreService.ChangePositionPriority(Guid posId, int priority)
        {
            var position = _positionRepository.GetById(posId);
            position.Priority = priority;
            _positionRepository.Update(position);
        }

        void ICoreService.ChangePositionDescription(Guid posId, string description)
        {
            var position = _positionRepository.GetById(posId);
            position.Description = description;
            _positionRepository.Update(position);
        }

        void ICoreService.DeletePosition(Guid positionId)
        {
            _positionRepository.Delete(positionId);
        }


        FeedTemplate ICoreService.CreateFeedTemplate(Guid appId, string titleTemplate, string bodyTemplate, int type)
        {
            throw new NotImplementedException();
        }

        void ICoreService.DeleteFeedTemplate(Guid id)
        {
            throw new NotImplementedException();
        }

        FeedTemplate ICoreService.GetFeedTemplateById(Guid templateId)
        {
            return _feedTemplateRepository.GetById(templateId);
        }

        IList<FeedTemplate> ICoreService.GetFeedTemplate(string templateName, Guid appId)
        {
            throw new NotImplementedException();
        } 
        
        IList<Group> ICoreService.GetAllSystemGroups()
        {
            return _groupRepository.GetAll()
                .Where(g => g.Type == 0)
                .ToList();
        }

    }
}
